package com.lzs.common.utils.easy;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import com.alibaba.fastjson.JSONObject;
import com.lzs.common.properties.PropertiesUtils;
import io.swagger.annotations.ApiModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URLEncoder;
import java.util.*;

//import com.github.tobato.fastdfs.domain.StorePath;
//import com.github.tobato.fastdfs.service.FastFileStorageClient;

/**
 * 梁子松
 * 使用easy poi导入导出
 */
@Slf4j
@Component
public class EasyExcelUtils {

    private static final String XLS_TYPE = ".xls";
    private static final String XLSX_TYPE = ".xlsx";

    /**
     * excel 导出
     * @param list           数据
     * @param title          标题
     * @param sheetName      sheet名称
     * @param pojoClass      pojo类型
     * @param isCreateHeader 是否创建表头
     * @param response
     */
    public void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, boolean isCreateHeader, HttpServletResponse response) {
        ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, response, exportParams);
    }

    /**
     * excel 导出
     *
     * @param list      数据
     * @param title     标题
     * @param sheetName sheet名称
     * @param pojoClass pojo类型
     * @param response
     * @return 文件路劲
     */
    public void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, HttpServletResponse response) {
        defaultExport(list, pojoClass, response, new ExportParams(title, sheetName, ExcelType.XSSF));
    }

    public static void exportExcel(List<?> list, Class<?> pojoClass, HttpServletResponse response) {
        ExportParams exportParams = new ExportParams();
        exportParams.setType(ExcelType.XSSF);
        ApiModel annotation = pojoClass.getAnnotation(ApiModel.class);
        String value = annotation.value();
        if (Objects.nonNull(annotation)) {
            exportParams.setTitle(value);
        }
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
        defaultExport(list, pojoClass, response, exportParams);
    }
    /**
     * excel 导出
     *
     * @param list         数据
     * @param pojoClass    pojo类型
     * @param response
     * @param exportParams 导出参数
     */
    public static void exportExcel(List<?> list, Class<?> pojoClass, ExportParams exportParams, HttpServletResponse response) {
        if (Objects.isNull(exportParams)) {
            exportParams = new ExportParams();
            exportParams.setType(ExcelType.XSSF);
        }
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
        defaultExport(list, pojoClass, response, exportParams);
    }

    /**
     * excel 导出
     *
     * @param list     数据
     * @param response
     */
    public static void exportExcel(List<Map<String, Object>> list, HttpServletResponse response) {
        defaultExport(list, response);
    }

    /**
     * 默认的 excel 导出
     *
     * @param list         数据
     * @param pojoClass    pojo类型
     * @param response
     * @param exportParams 导出参数
     */
    private static void defaultExport(List<?> list, Class<?> pojoClass, HttpServletResponse response, ExportParams exportParams) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        downLoadExcel( response, workbook);
    }

    /*
     * 默认的 excel 导出
     *
     * @param list     数据
     * @param fileName 文件名称
     * @param response
     */
    private static void defaultExport(List<Map<String, Object>> list, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        downLoadExcel(response, workbook);
    }

    public static void createExcel(List list,String url,Class clazz,ExportParams exportParams){
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams,clazz,list);
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(url);
            workbook.write(fileOutputStream);
            fileOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (Objects.nonNull(workbook)) {
                    workbook.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (Objects.nonNull(fileOutputStream)) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 下载
     *
     * @param response
     * @param workbook excel数据
     */
    public static void downLoadExcel(HttpServletResponse response, Workbook workbook) {
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(System.currentTimeMillis() + "." + ExcelTypeEnum.XLSX.getValue(), "UTF-8"));
            workbook.write(outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (Objects.nonNull(workbook)) {
                try {
                    workbook.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            if (Objects.nonNull(outputStream)) {
                try {
                    outputStream.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * excel 导入
     * 图片不可嵌入单元格，设置为浮动图片
     * @param filePath   excel文件路径
     * @param titleRows  标题行
     * @param headerRows 表头行
     * @param pojoClass  pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        params.setNeedSave(false);
//        params.setSaveUrl("/Users/liangzisong/Downloads/");
        try {
            return ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new IOException("模板不能为空");
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * excel 导入
     *
     * @param file      excel文件
     * @param pojoClass pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Class<T> pojoClass) throws IOException {
        String excelUploadImgSaveToLocalUrlVal = PropertiesUtils.getExcelUploadImgSaveToLocalUrlVal();
        System.out.println("excelUploadImgSaveToLocalUrlVal = " + excelUploadImgSaveToLocalUrlVal);
        //替换savePath
        changeAnnotationValue(pojoClass, Excel.class, "savePath", excelUploadImgSaveToLocalUrlVal);
        return importExcel(file, 1, 1, pojoClass);
    }

//    public static void main(String[] args) {
//        try {
//            Field[] fields = Test.class.getDeclaredFields();
//            for (Field field : fields) {
//                Excel annotation = field.getAnnotation(Excel.class);
//                Class<? extends Excel> aClass = annotation.getClass();
//                Method savePath = aClass.getMethod("savePath");
////                Field savePath = aClass.getDeclaredField("savePath");
//                savePath.setAccessible(true);
//                savePath.invoke()
//                Object defaultValue = savePath.getDeclaringClass();
//                System.out.println("defaultValue = " + defaultValue);
////                savePath.set("savePath","savePath");
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

    /**
     * 变更注解的属性值
     *
     * @param clazz     注解所在的实体类
     * @param tClass    注解类
     * @param filedName 要修改的注解属性名
     * @param value     要设置的属性值
     */
    public static <A extends Annotation> Class<?> changeAnnotationValue(Class<?> clazz, Class<A> tClass, String filedName, Object value) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                A annotation = field.getAnnotation(tClass);
                if (Objects.isNull(annotation)) {
                    continue;
                }
                setAnnotationValue(annotation, filedName, value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazz;
    }

    /**
     * 设置注解中的字段值
     *
     * @param annotation 要修改的注解实例
     * @param fieldName  要修改的注解属性名
     * @param value      要设置的属性值
     */
    public static void setAnnotationValue(Annotation annotation, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        InvocationHandler handler = Proxy.getInvocationHandler(annotation);
        Field field = handler.getClass().getDeclaredField("memberValues");
//        System.out.println("field = " + field);
        field.setAccessible(true);
        Map memberValues = (Map) field.get(handler);
        Object type = memberValues.get("type");
        if(Objects.nonNull(type) && (Integer)type == 2){
            memberValues.put(fieldName, value);
        }
    }

//    public static void main(String[] args) {
//        Class<Test> testClass = Test.class;
//        // 测试修改属性
//        changeAnnotationValue(testClass, Excel.class, "savePath", "123312");
//        try {
//            Field[] fields = testClass.getDeclaredFields();
//            for (Field field : fields) {
//                Excel annotation = field.getAnnotation(Excel.class);
//                System.out.println(annotation.savePath());
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }


    /**
     * excel 导入
     *
     * @param file       excel文件
     * @param titleRows  标题行
     * @param headerRows 表头行
     * @param pojoClass  pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
        return importExcel(file, titleRows, headerRows, false, pojoClass);
    }

    /**
     * excel 导入
     *
     * @param file       上传的文件
     * @param titleRows  标题行
     * @param headerRows 表头行
     * @param needVerfiy 是否检验excel内容
     * @param pojoClass  pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, boolean needVerfiy, Class<T> pojoClass) throws IOException {
        if (file == null) {
            return null;
        }
        try {
            return importExcel(file.getInputStream(), titleRows, headerRows, needVerfiy, pojoClass);
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * excel 导入
     *
     * @param inputStream 文件输入流
     * @param titleRows   标题行
     * @param headerRows  表头行
     * @param needVerfiy  是否检验excel内容
     * @param pojoClass   pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(InputStream inputStream, Integer titleRows, Integer headerRows, boolean needVerfiy, Class<T> pojoClass) throws IOException {
        if (inputStream == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
//        String saveToLocalUrlVal = PropertiesUtils.getExcelUploadImgSaveToLocalUrlVal();
//        params.setSaveUrl(saveToLocalUrlVal);
//        params.setNeedSave(true);
//        params.setSaveUrl();
        params.setNeedVerify(needVerfiy);
        try {
            return ExcelImportUtil.importExcel(inputStream, pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new IOException("excel文件不能为空");
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(e.getMessage());
        }
    }

//    public static void main(String[] args) throws Exception {
//        String filePath = "/Users/liangzisong/Desktop/testImport.xlsx";
//        List<Test> testList = EasyExcelUtils.importExcel(filePath, 1, 1, Test.class);
//        System.out.println("JSONObject.toJSONString(testList) = " + JSONObject.toJSONString(testList));
//    }

    /**
     * Excel 类型枚举
     */
    enum ExcelTypeEnum {
        XLS("xls"), XLSX("xlsx");
        private String value;

        ExcelTypeEnum(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}
